package com.xiaoshuidi.cloud.framework.yinlian.core.trade;

import com.alibaba.excel.EasyExcel;
import com.xiaoshuidi.cloud.framework.yinlian.config.YinlianFtpProperties;
import com.xiaoshuidi.cloud.framework.yinlian.core.trade.vo.YinlianTransactionExcelVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;

@Slf4j
@RequiredArgsConstructor
public class PullTransactionFlowServiceImpl implements PullTransactionFlowService {
    private final YinlianFtpProperties yinlianFtpProperties;
    private final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd");
    private FTPClient connect() throws IOException {
        FTPClient ftp = new FTPClient();
        log.info("连接银联Ftp: {}:{}", yinlianFtpProperties.getHost(), yinlianFtpProperties.getPort());
        ftp.connect(yinlianFtpProperties.getHost(), yinlianFtpProperties.getPort());
        if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
            log.error("银联FTP {}:******@{}:{} 拒绝连接", yinlianFtpProperties.getUsername(),
                    yinlianFtpProperties.getHost(), yinlianFtpProperties.getPort());
            ftp.disconnect();
            throw new IOException("银联FTP服务器[" + yinlianFtpProperties.getHost()
                    + ":" + yinlianFtpProperties.getPort() + "]连接失败");
        }
        if (ftp.login(yinlianFtpProperties.getUsername(), yinlianFtpProperties.getPassword())) {
            ftp.enterLocalPassiveMode();
            ftp.setFileTransferMode(FTP.BLOCK_TRANSFER_MODE);
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            ftp.setBufferSize(1024 * 1024);
            if (FTPReply.isPositiveCompletion(ftp.sendCommand("OPTS UTF8", "ON"))) {
                ftp.setControlEncoding("UTF-8");
            } else {
                ftp.setControlEncoding("GBK");
            }
        } else {
            throw new IOException("银联FTP服务器[" + yinlianFtpProperties.getHost()
                    + ":" + yinlianFtpProperties.getPort() + "]登录失败");
        }
        return ftp;
    }

    @Override
    public <T> void pull(String merchantCode, LocalDate date, YinlianExcelConsumer<T> consumer) throws IOException {
        FTPClient ftp = connect();
        Path workDir = Paths.get(ftp.printWorkingDirectory(), yinlianFtpProperties.getDir());
        if (!ftp.changeWorkingDirectory(workDir.toString())) {
            throw new IOException("目录: " + yinlianFtpProperties.getDir() + "不存在");
        }
        Pattern fileRegex = Pattern.compile(yinlianFtpProperties.getFilePattern());
        try {
            FTPFile[] files = ftp.listFiles();
            log.info("拉取文件: {}[{}] {} {}", files.length, workDir, merchantCode, date);
            for (FTPFile file : files) {
                if (file.getName().startsWith(".")) {
                    continue;
                }
                log.info("{}", file.getName());
                if (!fileRegex.matcher(file.getName()).matches()) {
                    log.info("文件过滤: {}/{}", file.getName(), fileRegex.pattern());
                    continue;
                }
                if (file.getName().startsWith(String.format("%s_%s", merchantCode, date.format(fmt)))) {
                    log.info("解析文件: {}", file.getName());
                    consumer.setFileName(file.getName());
                    InputStream os = ftp.retrieveFileStream(file.getName());
                    EasyExcel.read(os, YinlianTransactionExcelVO.class, new DefaultYinlianExcelReadListener<>(consumer))
                            .headRowNumber(3)
                            .doReadAll();
                    break;
                }
            }
        } catch (Exception e) {
            log.error("获取文件列表异常", e);
        } finally {
            disconnect(ftp);
        }
    }

    private void disconnect(FTPClient client) throws IOException {
        if (client != null) {
            if (!client.isConnected()) {
                return;
            }
            boolean logoutSuccess = client.logout();
            client.disconnect();
            if (!logoutSuccess) {
                log.warn("Logout failed while disconnecting, error code - "
                        + client.getReplyCode());
            }
        }
    }
}
